// exception.cc 
//	Entry point into the Nachos kernel from user programs.
//	There are two kinds of things that can cause control to
//	transfer back to here from user code:
//
//	syscall -- The user code explicitly requests to call a procedure
//	in the Nachos kernel.  Right now, the only function we support is
//	"Halt".
//
//	exceptions -- The user code does something that the CPU can't handle.
//	For instance, accessing memory that doesn't exist, arithmetic errors,
//	etc.  
//
//	Interrupts (which can also cause control to transfer from user
//	code into the Nachos kernel) are handled elsewhere.
//
// For now, this only handles the Halt() system call.
// Everything else core dumps.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "system.h"
#include "syscall.h"

//----------------------------------------------------------------------
// AdvancePC
// 	Make PC count one
//----------------------------------------------------------------------

void AdvancePC()
{
  int pc;

  pc = machine->ReadRegister(PCReg);
  machine->WriteRegister(PrevPCReg, pc);
  pc = machine->ReadRegister(NextPCReg);
  machine->WriteRegister(PCReg, pc);
  pc += 4;
  machine->WriteRegister(NextPCReg, pc);
}

//----------------------------------------------------------------------
// ExceptionHandler
// 	Entry point into the Nachos kernel.  Called when a user program
//	is executing, and either does a syscall, or generates an addressing
//	or arithmetic exception.
//
// 	For system calls, the following is the calling convention:
//
// 	system call code -- r2
//		arg1 -- r4
//		arg2 -- r5
//		arg3 -- r6
//		arg4 -- r7
//
//	The result of the system call, if any, must be put back into r2. 
//
// And don't forget to increment the pc before returning. (Or else you'll
// loop making the same system call forever!
//
//	"which" is the kind of exception.  The list of possible exceptions 
//	are in machine.h.
//----------------------------------------------------------------------

void
ExceptionHandler(ExceptionType which)
{
    	int type = machine->ReadRegister(2);

	if ((which == SyscallException) && (type == SC_Halt)) {
		DEBUG('a', "Shutdown, initiated by user program.\n");
		interrupt->Halt();
	}
	else if(type==SC_Create){
		DEBUG('a', "Create, initiated by user program.\n");
		printf("Exception Create\n");
		int fileNameAddr=(int)machine->ReadRegister(4);
		char* fileName=new char[256];
		int ch=-1;

		int fileNameI;
		for (fileNameI=0;ch!=0&&fileNameI<256;++fileNameI)
		{
		  machine->ReadMem(fileNameAddr+fileNameI,1,&ch);
		  fileName[fileNameI]=(char)ch;
		}
		ASSERT(fileNameI<256);
		printf("name: %s\n",fileName);

		interrupt->Create(fileName);

		AdvancePC();
	}
	else if(type==SC_Open){
		DEBUG('a', "Open, initiated by user program.\n");
		printf("Exception Open\n");
		int fileNameAddr=(int)machine->ReadRegister(4);
		char* fileName=new char[256];
		int ch=-1;
		int fileNameI;
		for (fileNameI=0;ch!=0&&fileNameI<256;++fileNameI) {
		  machine->ReadMem(fileNameAddr+fileNameI,1,&ch);
		  fileName[fileNameI]=(char)ch;
		}
		ASSERT(fileNameI<256);
		printf("name: %s\n",fileName);
		int OpenfileId;
		OpenfileId=interrupt->Open(fileName);
		printf("OpenfileId: %d\n",OpenfileId);
		machine->WriteRegister(2,OpenfileId);
		AdvancePC();
	}
	else if(type==SC_Close){
		DEBUG('a', "Close, initiated by user program.\n");
		printf("Exception Close\n");
		int id=machine->ReadRegister(4);
		interrupt->Close(id);
		AdvancePC();
	}
	else if(type==SC_Write){
		DEBUG('a', "Write, initiated by user program.\n");
		printf("Exception Write\n");
		int bufferIndex=(int)machine->ReadRegister(4);

		int size=machine->ReadRegister(5);
		int id=machine->ReadRegister(6);
		interrupt->Write(bufferIndex, size, id);
		AdvancePC();
	}
	else if(type==SC_Read){
		DEBUG('a', "Read, initiated by user program.\n");
		printf("Exception Read\n");
		int bufferIndex=(int)machine->ReadRegister(4);
		int size=machine->ReadRegister(5);
		int id=machine->ReadRegister(6);
		interrupt->Read(bufferIndex, size, id);
		AdvancePC();
	}
	else if(type==SC_Exec){
		DEBUG('a', "Exec, initiated by user program.\n");
		printf("Exception Exec\n");
		int SpaceId;
		int SC_Exec_name_addr=(int)machine->ReadRegister(4);
		//程序名
		char* SC_Exec_name=new char[256];
		int SC_Exec_ch=-1;
		int SC_Exec_name_i;
		for (SC_Exec_name_i=0;SC_Exec_ch!=0&&SC_Exec_name_i<256;++SC_Exec_name_i) {
		  machine->ReadMem(SC_Exec_name_addr+SC_Exec_name_i,1,&SC_Exec_ch);
		  SC_Exec_name[SC_Exec_name_i]=(char)SC_Exec_ch;
		}
		ASSERT(SC_Exec_name_i<256);
		printf("name: %s\n",SC_Exec_name);
		SpaceId=interrupt->Exec(SC_Exec_name);
		machine->WriteRegister(2,SpaceId);
		printf("SpaceId:%d\n",SpaceId);
		AdvancePC();
	}
	else if(type==SC_Join){
		DEBUG('a', "Join, initiated by user program.\n");
		printf("Exception fork\n");
		int SpaceId=(int)machine->ReadRegister(4);
		interrupt->Join(SpaceId);
		AdvancePC();
	}
	else if(type==SC_Exit){
		DEBUG('a', "Shutdown, initiated by user program.\n");
		printf("Exception Exit\n");
		int status=machine->ReadRegister(4);
		printf("status %d\n",status);
		interrupt->Exit(status);
		AdvancePC();
	}
	else if (type==SC_Fork)
	{
		DEBUG('a', "Fork, initiated by user program.\n");
		printf("Exception Fork\n");
		interrupt->Fork();
		AdvancePC();
	}
	else if(type==SC_Yield){
		DEBUG('a', "Yield, initiated by user program.\n");
		printf("Exception Yield\n");
		interrupt->Yield();
		AdvancePC();
	}
 	else {
		printf("Unexpected user mode exception %d %d\n", which, type);
		ASSERT(FALSE);
    	}
}

